package com.ian.config;

import com.ian.annotation.WithMockCustomUser;
import com.ian.entity.CustomUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.test.context.support.WithSecurityContextFactory;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.util.Assert;

import java.util.HashSet;
import java.util.Set;

/**
 * 这个工厂不能用，只是做一个说明。
 *
 * 创建 SecurityContext 实例的工厂
 * 工厂方法模式（定义了一个创建对象的接口，但是让子类决定实例化哪个类。工厂方法推迟了一个类的实例化动作到子类）
 *
 * When creating your own WithSecurityContextFactory implementations, it is nice to know that they can be annotated with standard Spring annotations. For example, the WithUserDetailsSecurityContextFactory uses the @Autowired annotation to acquire the UserDetailsService:
 * @author Witt
 * @version 1.0.0
 * @date 2022/5/14
 */
public class WithUserDetailsSecurityContextFactory implements WithSecurityContextFactory<WithUserDetails> {

    private UserDetailsService userDetailsService;

    @Autowired
    public WithUserDetailsSecurityContextFactory(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public SecurityContext createSecurityContext(WithUserDetails withUserDetails) {

        SecurityContext context = SecurityContextHolder.createEmptyContext();
        // create a UserDetails instance
        String username = withUserDetails.value();
        Assert.hasLength(username, "value() must be non-empty String");
        UserDetails principal = userDetailsService.loadUserByUsername(username);

        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(principal, "password1", principal.getAuthorities());
        context.setAuthentication(authentication);
        return context;
    }
}
